#ifndef SQL_COLLECTION_VIEW_HPP
#define SQL_COLLECTION_VIEW_HPP

#include "config.h"

#include <app/app_base.hpp>
#include <event/events.hpp>
#include <utils/singleton.hpp>
#include <vector>
#include "sql/sql_driver.hpp"

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4251)
#endif

template <typename Type, typename Event>
class SqlCollectionView final: public PublicSingleton<SqlCollectionView<Type, Event>> {
    friend PublicSingleton<SqlCollectionView<Type, Event>>;

public:
    using Collection = std::vector<Type>;
    using ReadMemFn = Collection(ISqlDriver::*)()const;
    
    const Collection& Const() const { return collection_; }
    Collection& Mutable() { return collection_; }
private:
    SqlCollectionView(): listener(App->Bus()), the_driver(App->Sql()) {
        listener.listen<Event>([this](const auto&){ UpdateCollection(); });
        UpdateCollection();
    }
    ~SqlCollectionView() {
        listener.unlistenAll();
    }

    void UpdateCollection() {
        collection_ = (the_driver->*s_reload)();
    }

    Listener    listener;
    ISqlDriver *the_driver;
    Collection  collection_;

    static ReadMemFn s_reload;
};


#define DECLARE_SQL_VIEW(Type, Event) \
template class DIARY_APP_SDK_API SqlCollectionView<Type, Event>; \
using Type##SqlView = SqlCollectionView<Type, Event>;

#define IMPL_SQL_VIEW(Type, ReadMember) \
template<> Type##SqlView::ReadMemFn Type##SqlView::s_reload = ReadMember;

#define SqlViewOf(T) T##SqlView::Instance().Const()
#define SqlViewOfMut(T) T##SqlView::Instance().Mutable()

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif /* SQL_COLLECTION_VIEW_HPP */
